package eiisan.lucenedemo;

import org.apache.lucene.document.Document;
import org.apache.lucene.document.LongPoint;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.FSDirectory;
import org.junit.Before;
import org.junit.Test;
import org.wltea.analyzer.lucene.IKAnalyzer;

import java.io.File;
import java.io.IOException;

/**
 * @description: 索引库的查询
 * 使用Query的子类
 *
 * 参考：https://blog.csdn.net/u013573133/article/details/48246351
 * 几种查询方式
 *
 * 查询方式                      说明
 *
 * TermQuery       条件查询
 *                 例如：TermQuery tquery=new TermQuery(new Term("name","jerry"));
 *                 name:字段名
 *                 jerry:要搜索的字符串
 *
 * MultiTermQuery  多个字段进行同一关键字的查询
 *                 Query query= null;
 *                 Query =MultiFieldQueryParser.parse("我",new String[] 学习lucene - 风 - 杨超峰的博客{"title","content"},analyzer);
 *                 Searcher searcher=new IndexSearcher(indexFilePath);
 *                 Hits hits=searcher.search(query);
 *
 * BooleanQuery    例如：BooleanQuery bquery=new BooleanQuery();
 *                 bquery.add(query,true,false);
 *                 bquery.add(mquery,true,false);
 *                 bquery.add(tquery,true,false);
 *                 Searcher searcher=new IndexSearcher(indexFilePath);
 *                 Hits hits=searcher.search(bquery);
 *
 * WildcardQuery    语义查询（通配符查询）
 *                  例：Query query= new WildcardQuery(new Term("sender","*davy*"));
 *
 * PhraseQuery       短语查询
 *
 * PrefixQuery       前缀查询
 *
 * PhrasePrefixQuery 短语前缀查询
 *
 * FuzzyQuery        模糊查询
 *
 * RangeQuery        范围查询
 *
 * SpanQuery         范围查询
 *
 *
 * @author: eii
 * @time: 2020/8/8 12:36 上午
 */
public class LuceneQuery {
    private IndexReader indexReader;
    private IndexSearcher indexSearcher;

    @Before
    public void init() throws IOException {
        indexReader = DirectoryReader.open(FSDirectory.open(new File("/Users/eii/tmp/index").toPath()));
        indexSearcher = new IndexSearcher(indexReader);
    }

    @Test
    public void testQuery() throws IOException {
        //创建一个Query对象
        Query query = LongPoint.newRangeQuery("size",0l,100l);
        printResult(query);
    }

    private void printResult(Query query) throws IOException {
        TopDocs topDocs = indexSearcher.search(query, 10);
        System.out.println("查询到的总记录数：" + topDocs.totalHits);
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        for (ScoreDoc scoreDoc : scoreDocs) {
            int docId = scoreDoc.doc;
            Document doc = indexSearcher.doc(docId);
            System.out.println("name:"+ doc.get("name"));
            System.out.println("path:"+ doc.get("path"));
            System.out.println("content:"+ doc.get("content"));
        }
        System.out.println("================================");
    }


    @Test
    public void testQueryParser() throws IOException, ParseException {
        //创建一个QueryPaser对象，两个参数
        QueryParser queryParser = new QueryParser("name", new IKAnalyzer());
        //参数1：默认搜索域，参数2：分析器对象
        //使用QueryPaser对象创建一个Query对象
        Query query = queryParser.parse("lucene是一个Java开发的全文检索工具包");
        //执行查询
        printResult(query);
    }


    /*
在全文检索时建议大家先采用语义时的搜索，先搜索出有意义的内容，之后再进行模糊之类的搜索
(1)联合两个索引查询，已解决：
    IndexSearcher[] searchers = new IndexSearcher[2];
    searchers[0] = new IndexSearcher(m_indexpath);
    searchers[1] = new IndexSearcher(m_outindexpath);
    MultiSearcher multiSearcher = new MultiSearcher(searchers);v

(2)还有个进行多条件搜索 and 与 or 的操作

用 MultiFieldQueryParser
建议重新封装
MultiFieldQueryParser.Parser(p[],d[],f[],analyer)  成or 与 and操作合一
或者
BooleanQuery m_BooleanQuery = new BooleanQuery();
Query query = QueryParser.Parse(m_SearchText, "INSTRUMENT_NAME", analyzer);
Query query2 = QueryParser.Parse(m_SearchText2, "INSTRUMENT_NAME2", analyzer);
m_BooleanQuery.Add(query, true, false);
m_BooleanQuery.Add(query2, true, false);

(3)复合查询（多种查询条件的综合查询）
Query query=MultiFieldQueryParser.parse("索引”,new String[]{"title","content"},analyzer);
Searcher searcher=new IndexSearcher(indexFilePath);
Hits hits=searcher.search(query);
for (int i = 0; i < hits.length(); i++) 学习lucene - 风 - 杨超峰的博客{
  System.out.println(hits.doc(i).get("name"));
}

5.为查询优化索引(index)
Indexwriter.optimize()方法可以为查询优化索引（index），
之前提到的参数调优是为indexing过程本身优化，而这里是为查询优化，
优化主要是减少index文件数，这样让查询的时候少打开文件，
优化过程中，lucene会拷贝旧的index再合并，合并完成以后删除旧的index，
所以在此期间，磁盘占用增加， IO符合也会增加，在优化完成瞬间，
磁盘占用会是优化前的2倍,在optimize过程中可以同时作search。

     */

}
